const path = require('path');
const fs = require('fs')
const { getAst, getDeps, getCode } = require('./parse');

class Compiler {
  constructor(options = {}) {
    // webpack配置
    this.options = options;
    // 所有依赖容器
    this.modules = []
  }
  // 启动webpack打包
  run() {
    // 1.读取入口文件
    const filePath = this.options.entry;
    // 第一次构建，得到的入口文件信息
    const fileInfo = this.build(filePath)
    this.modules.push(fileInfo);
    // 遍历所有依赖
    this.modules.forEach(fileInfo => {
      /**
       * {
            './add.js': '/Users/feng/Documents/workspace/webpack-demo/myWebpack/src/add.js',
            './minus.js': '/Users/feng/Documents/workspace/webpack-demo/myWebpack/src/minus.js'
          }
       *  */
      // 取出当前文件的所有依赖
      const deps = fileInfo.deps;
      for (const relativePath in deps) {
        // 依赖文件的绝对路径
        const absolutePath = deps[relativePath];
        // 对依赖文件进行处理
        const fileInfo = this.build(absolutePath);
        // 将处理后的结果添加到modules中，后面遍历就会遍历它？存疑
        this.modules.push(fileInfo);
      }
    });
    console.log(this.modules)

    // 将依赖整理成更好的依赖关系图

    /**
     * {
     *  'index.js':{
     *    code: 'xxx',
     *    deps:{'add.js':'xxx'}
     *  },
     * 'add.js':{
     *    code: 'xxx',
     *    deps:{}
     *  },
     * 
     * }
     */
    const depsGraph = this.modules.reduce((graph, module) => {
      return {
        ...graph,
        [module.filePath]: {
          code: module.code,
          deps: module.deps
        }
      }
    }, {})
    console.log(depsGraph);
    this.generate(depsGraph);
  }

  build(filePath) {
    const ast = getAst(filePath);
    const deps = getDeps(ast, filePath);
    const code = getCode(ast)
    return {
      filePath,
      deps,
      code,
      ast
    }
  }

  generate(depsGraph) {
    /**
     * "use strict";\n' +
      '\n' +
      'var _add = _interopRequireDefault(require("./add.js"));\n' +
      '\n' +
      'var _minus = _interopRequireDefault(require("./minus.js"));\n' +
      '\n' +
      'function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n' +
      '\n' +
      'console.log((0, _add["default"])(1, 2));\n' +
      'console.log((0, _minus["default"])(1, 2));
     */
    const bundle = `
      (function(depsGraph){
        // require目的，加载入口文件
        function require(module){
          // 定义模块内部的require
          function localRequire(relativePath){
            // 为了找到要引入模块的路径，通过require函数加载
            return require(depsGraph[module].deps[relativePath])
          }
          // 定义的暴露对象（将来我们模块要暴露的内容
          var exports = {};
          (function(require,exports,code){
            eval(code);
          })(localRequire,exports,depsGraph[module].code)
          // 作为require函数返回值返回出去
          // 后面require函数能得到暴露的内容
          return exports;
        }
        // 加载入口文件
        require('${this.options.entry}')
      }(${JSON.stringify(depsGraph)}))
    `
    // 生成输出的绝对路径
    const filePath = path.resolve(this.options.output.path, this.options.output.filename);
    console.log(filePath)
    // 写出
    fs.writeFileSync(filePath, bundle, 'utf-8');
  }
}

module.exports = Compiler